home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Developer Essentials / DTS Sample Code / System 7.0 Samples / ProcDoggie 1.0a6 / UDialogUtils.inc1.p < prev    next >
Encoding:
Text File  |  1991-02-07  |  16.9 KB  |  467 lines  |  [TEXT/MPS ]

  1. {-------------------------------------------------------------------------------
  2. #
  3. #    Apple Macintosh Developer Technical Support
  4. #
  5. #    Code for the dialog utilities
  6. #
  7. #    Program:    ProcDoggie
  8. #    File:        UDialogUtils.inc1.p - Pascal Implementation
  9. #
  10. #    by:        Forrest Tanaka
  11. #
  12. #    Copyright © 1988-1991 Apple Computer, Inc.
  13. #    All rights reserved.
  14. #
  15. -------------------------------------------------------------------------------}
  16. {[j=20/57/1$] Pasmat Options}
  17. {$R-}
  18.  
  19.  
  20. (*******************************************************************************
  21. * Types
  22. *******************************************************************************)
  23.  
  24.     TYPE
  25.         TextStRec = PACKED RECORD
  26.             fontIndex: Byte;       {Index into STR# rsrc of font name for text}
  27.             statStyle: Byte;       {Style of static text}
  28.             statSize:  Byte;       {Point size of static text}
  29.             statJust:  SignedByte; {Justification of static text}
  30.         END;
  31.  
  32.         DITLTmplRec = PACKED RECORD
  33.             pad0:        TextStRec;  {Text style for static text items}
  34.             displayRect: Rect;       {Rect in which to display item in wind coords}
  35.             itemType:    Byte;       {Type of item}
  36.             dataLen:     Byte;       {Length of item data}
  37.             CASE Integer OF
  38.                 0: (itemRes:  Integer);
  39.                 1: (itemText: PACKED ARRAY [0..239] OF Char)
  40.         END;
  41.         DITLTmplPtr = ^DITLTmplRec;
  42.  
  43.         ItemRec = RECORD
  44.             displayRect: Rect;        {Display item rect in window coords}
  45.             refCon:      LongInt;     {Used for anything client wants}
  46.             dismissor:   Boolean;     {True if the item is a dismissor}
  47.             CASE itemType: Integer OF {Code for item type or 0 if last item}
  48.                 0: (itemControl:  ControlHandle); {Handle to item control}
  49.                 1: (itemText:     Handle;         {Handle to text of static text}
  50.                      itemTypeInfo: TypeInfoRec)    {Type info for static text}
  51.         END;
  52.         ItemListArr = ARRAY [0..255] OF ItemRec;
  53.         ItemListPtr = ^ItemListArr;
  54.         ItemListHnd = ^ItemListPtr;
  55.  
  56.  
  57. {$S DialogUtils}
  58. (*******************************************************************************
  59. * Public: InstallDialogItems
  60. *
  61. * This routine is mainly a DITL-resource interpreter.  After loading the DITL
  62. * resource with a resource ID passed in itemListNum into memory, it reads the
  63. * information in it to build up an array of dialog items in an ItemListArr,
  64. * which is defined in the TYPE section of this source file.  This routine
  65. * allocates the item array and attaches it to the "items" field of the specified
  66. * DialogRecord.  Once the item array is filled, the DITL is no longer needed and
  67. * is made purgeable.
  68. *
  69. * Currently, this routine handles push buttons and static text fields.  Push
  70. * buttons are simply handled by calling NewControl.  The resulting ControlHandle
  71. * is placed into the itemControl field of the ItemRec.  For static text items,
  72. * a handle to the text is placed into itemText and the style information is
  73. * placed into the itemTypeInfo.
  74. *
  75. * Static text items are handled a little differently, and involves a change to
  76. * the DITL structure.  I’ve kept the size of the DITL the same as it ever was,
  77. * but the four bytes that are described as a “placeholder for handle or
  78. * procedure pointer” on page 427 of Inside Macintosh I are now interpreted by
  79. * InstallDialogItems to hold font information for static text items.  This font
  80. * information has the structure described by TextStRec which is declared in the
  81. * TYPE section of this source file.  This is a four-byte record that holds the
  82. * type face, type style, type size, and justification (really alignment) of the
  83. * static text item.  InstallDialogItems converts this into a TypeInfoRec
  84. * (declared in the UDialogUtils.p file) which is then placed into the item
  85. * array.  When DrawDialogItems is called, it draws static text items using this
  86. * font information.
  87. *
  88. * The TextStRec consists of four bytes.  The first bytes specifies the type
  89. * face to use for the static text.  It doesn’t specify the font number because
  90. * font numbers for a particular type face can vary from system to system.
  91. * Instead, this field holds an index into a STR# resource which holds a list of
  92. * font names.  The STR# resource must have a resource ID equal to the resource
  93. * ID of the DITL being read, that is, "itemListNum."
  94. *
  95. * The second byte specifies the style that the static text is meant to be drawn
  96. * in.  It holds the same value as the Style type.  The Style type is 16 bits
  97. * wide, so I declared this field as a Byte instead.  The third byte specifies
  98. * the size of text to use.  Of course, being a byte, it’s limited to a point
  99. * size of 255 points.  I didn’t think that’d be much of a problem, and you can
  100. * always draw the text yourself if you needed something larger.  The last byte
  101. * specifies the alignment of text in the static text item rectangle.  This field
  102. * can have the values teFlushRight, teFlushLeft, teFlushDefault, and teCenter.
  103. *
  104. * I wanted to keep the DITL mechanism so that Rez and particularly ResEdit could
  105. * still be used to edit the DITL, even though the Dialog Manager isn’t being
  106. * used with these kinds of dialogs.  Unfortunately, I had to redefine the Rez
  107. * DITL template so that it could take the static text font information, and
  108. * worse, ResEdit won’t edit DITLs that have non-zero values in the location that
  109. * I’m reading the font information.  So, keeping the DITL isn’t any particular
  110. * advantage over defining a completely new structure.  But, I’ll leave it this
  111. * ways for now.  There ARE other resource editors that might not be quite so
  112. * quick to criticize my DITLs.
  113. *
  114. * If all the dialog items were installed correctly, then noErr is returned.  If
  115. * any error happend, then the operating system result code is returned and the
  116. * dialog item list is disposed of, leaving aDialog unaffected.
  117. *******************************************************************************)
  118.  
  119.     FUNCTION InstallDialogItems (aDialog:     DialogPtr;
  120.                                  itemListNum: Integer): OSErr;
  121.  
  122.         TYPE
  123.             IntPtr = ^Integer;
  124.  
  125.         VAR
  126.             numItems:     Integer;       {Number of items in item list}
  127.             itemNum:      Integer;       {Item number of item we’re installing}
  128.             itemKind:     Integer;       {Type of the item}
  129.             fontNumber:   Integer;       {Font number of static text item}
  130.             ditlItemPtr:  DITLTmplPtr;   {Pointer to each item}
  131.             ditlList:     Handle;        {Handle to DITL resource}
  132.             itemList:     ItemListHnd;   {Handle to the item list}
  133.             aControl:     ControlHandle; {Handle to a control we’re installing}
  134.             aString:      Str255;        {String used for a couple of things}
  135.             staticText:   Handle;        {Handle to text for static text item}
  136.             dataLen:      Integer;       {Length of item data, rounded up to even}
  137.             doesDismiss:  Boolean;       {True if the item is a dismissor}
  138.  
  139.         PROCEDURE RecoverError (error: Integer);
  140.  
  141.         BEGIN
  142.             IF ditlList <> NIL THEN
  143.                 BEGIN
  144.                     HUnlock (ditlList);
  145.                     HPurge (ditlList)
  146.                 END;
  147.             IF itemList <> NIL THEN
  148.                 DisposeDialogItems (aDialog);
  149.             DialogPeek(aDialog)^.items := NIL;
  150.             InstallDialogItems := error;
  151.             EXIT (InstallDialogItems)
  152.         END;
  153.  
  154.     BEGIN
  155.         ditlList := NIL;
  156.         itemList := NIL;
  157.  
  158.         (* Grab the requested DITL resource *)
  159.         ditlList := GetResource ('DITL', itemListNum);
  160.         IF ditlList = NIL THEN
  161.             IF ResError = noErr THEN
  162.                 RecoverError (resNotFound)
  163.             ELSE
  164.                 RecoverError (ResError);
  165.  
  166.         (* Make sure we don’t lose it while we’re reading from it *)
  167.         HNoPurge (ditlList);
  168.  
  169.         (* Allocate item list; add 1 for flag record and 1 for numItems-1 adj *)
  170.         numItems := IntPtr(ditlList^)^;
  171.         itemList := ItemListHnd(NewHandleMargin (SIZEOF (ItemRec) * (numItems +
  172.                 2), kAllocApp, NOT kAllocClr));
  173.         IF itemList = NIL THEN
  174.             RecoverError (memFullErr);
  175.  
  176.         (* Fill with kNoItem items in case of error while building item list *)
  177.         FOR itemNum := 0 TO numItems + 1 DO
  178.             itemList^^ [itemNum].itemType := kNoItem;
  179.  
  180.         (* Put the item list into the dialog record *)
  181.         DialogPeek(aDialog)^.items := Handle(itemList);
  182.  
  183.         (* Point at the first item in the DITL *)
  184.         HLock (ditlList);
  185.         ditlItemPtr := DITLTmplPtr(ORD4(ditlList^) + SIZEOF (Integer));
  186.  
  187.         (* For each item in DITL, install into item list *)
  188.         FOR itemNum := 0 TO numItems DO
  189.             BEGIN
  190.                 (* Get the type of the item *)
  191.                 itemKind := ditlItemPtr^.itemType;
  192.  
  193.                 (* If itemDisable flag clear, item is a dismissor *)
  194.                 IF itemKind < 128 THEN
  195.                     doesDismiss := TRUE
  196.                 ELSE
  197.                     BEGIN
  198.                         doesDismiss := FALSE;
  199.                         itemKind := itemKind - 128
  200.                     END;
  201.  
  202.                 (* Grab the item information *)
  203.                 IF itemKind = ctrlItem + btnCtrl THEN
  204.                     BEGIN
  205.                         (* Copy control’s title to controlTitle *)
  206.                         BlockMove (@ditlItemPtr^.dataLen, @aString, ditlItemPtr^.
  207.                                 dataLen + 1);
  208.  
  209.                         (* Create the new control *)
  210.                         aControl := NewControl (aDialog, ditlItemPtr^.displayRect,
  211.                                 aString, TRUE, 0, 0, 0, pushButProc, 0);
  212.  
  213.                         (* Put the control’s handle into our item list *)
  214.                         itemList^^ [itemNum].itemType := itemKind;
  215.                         itemList^^ [itemNum].itemControl := aControl;
  216.  
  217.                         (* Bail if there’s not enough memory *)
  218.                         IF FailLowMemory (0) THEN
  219.                             RecoverError (memFullErr)
  220.                         ELSE IF aControl = NIL THEN
  221.                             IF (ResError = noErr) | (ResError = resNotFound) THEN
  222.                                 RecoverError (resNotFound)
  223.                             ELSE
  224.                                 RecoverError (ResError);
  225.  
  226.                         (* Put the control’s item number into the control’s refCon *)
  227.                         SetCRefCon (aControl, itemNum)
  228.                     END
  229.                 ELSE IF itemKind = statText THEN
  230.                     BEGIN
  231.                         (* Allocate space for text *)
  232.                         staticText := NewHandleMargin (ditlItemPtr^.dataLen,
  233.                                 kAllocApp, NOT kAllocClr);
  234.  
  235.                         (* Put the control’s handle into our item list *)
  236.                         itemList^^ [itemNum].itemType := itemKind;
  237.                         itemList^^ [itemNum].itemText := staticText;
  238.  
  239.                         (* Bail if there’s not enough memory for the text *)
  240.                         IF staticText = NIL THEN
  241.                             RecoverError (memFullErr);
  242.  
  243.                         (* Copy DITL text to our text handle *)
  244.                         BlockMove (@ditlItemPtr^.itemText, staticText^, ditlItemPtr^.
  245.                                 dataLen);
  246.  
  247.                         (* Put a handle to the text into our item list *)
  248.                         aString [0] := CHR (0);
  249.                         IF ditlItemPtr^.pad0.fontIndex > 0 THEN
  250.                             BEGIN
  251.                                 GetIndString ((*<*)aString, itemListNum, ditlItemPtr^.
  252.                                         pad0.fontIndex);
  253.                                 IF aString [0] = CHR (0) THEN
  254.                                     GetIndString ((*<*)aString, 0, ditlItemPtr^.pad0.
  255.                                             fontIndex)
  256.                             END;
  257.                         IF aString [0] = CHR (0) THEN
  258.                             fontNumber := 0
  259.                         ELSE
  260.                             GetFNum (aString, (*<*)fontNumber);
  261.                         itemList^^ [itemNum].itemTypeInfo.typeFace := fontNumber;
  262.                         itemList^^ [itemNum].itemTypeInfo.typeSize := ditlItemPtr^.
  263.                                 pad0.statSize;
  264.                         itemList^^ [itemNum].itemTypeInfo.textJust := ditlItemPtr^.
  265.                                 pad0.statJust;
  266.                         itemList^^ [itemNum].itemTypeInfo.typeStyle :=
  267.                                 Style(ditlItemPtr^.pad0.statStyle)
  268.                     END
  269.                 ELSE
  270.                     itemList^^ [itemNum].itemType := itemKind;
  271.  
  272.                 (* Copy interesting characteristics to our item list *)
  273.                 WITH itemList^^ [itemNum] DO
  274.                     BEGIN
  275.                         (*WITH*)displayRect := ditlItemPtr^.displayRect;
  276.                         (*WITH*)refCon := 0;
  277.                         (*WITH*)dismissor := doesDismiss
  278.                     END;
  279.  
  280.                 (* Bump the pointer to the next item in the DITL *)
  281.                 dataLen := BAnd (ditlItemPtr^.dataLen + 1, $FFFE);
  282.                 ditlItemPtr := DITLTmplPtr(ORD4(@ditlItemPtr^.itemText) + dataLen)
  283.             END;
  284.  
  285.         (* Don’t need the dialog item list any more *)
  286.         HUnlock (ditlList);
  287.         HPurge (ditlList);
  288.     END;
  289.  
  290.  
  291. {$S DialogUtils}
  292. (*******************************************************************************
  293. * Public: SetStatTextItem
  294. *
  295. * The text of a static text item is specified by a handle to the text, so that
  296. * handle is resized to the new text length, if needed, and then the text is
  297. * simply BlockMoved in.
  298. *******************************************************************************)
  299.  
  300.     PROCEDURE SetStatTextItem (aDialog:    DialogPtr;
  301.                                itemNum:    Integer;
  302.                                textPtr:    Ptr;
  303.                                textLength: Integer);
  304.  
  305.         VAR
  306.             itemList:   ItemListHnd; {Handle to item list}
  307.             textHandle: Handle;      {Handle to the existing item text}
  308.  
  309.     BEGIN
  310.         (* Grab the item list from the dialog window’s refCon *)
  311.         itemList := ItemListHnd(DialogPeek(aDialog)^.items);
  312.  
  313.         (* If the item is indeed a static text item, then set it *)
  314.         IF itemList^^ [itemNum].itemType = statText THEN
  315.             BEGIN
  316.                 textHandle := itemList^^ [itemNum].itemText;
  317.                 IF NOT FailLowMemory (textLength) THEN
  318.                     BEGIN
  319.                         IF GetHandleSize (textHandle) <> textLength THEN
  320.                             SetHandleSize (textHandle, textLength);
  321.                         BlockMove (textPtr, textHandle^, textLength)
  322.                     END
  323.             END
  324.     END;
  325.  
  326.  
  327. {$S DialogUtils}
  328. (*******************************************************************************
  329. * Public: GetStatTextFontInfo
  330. *
  331. * Font information for a static text item is simply stored in its itemTypeInfo
  332. * field.  It’s a simple matter of copying this record into "typeInfo".
  333. *******************************************************************************)
  334.  
  335.     PROCEDURE GetStatTextFontInfo (aDialog:      DialogPtr;
  336.                                    itemNum:      Integer;
  337.                                    VAR typeInfo: TypeInfoRec);
  338.  
  339.         VAR
  340.             itemList: ItemListHnd; {Handle to item list}
  341.  
  342.     BEGIN
  343.         (* Grab the item list from the dialog window’s refCon *)
  344.         itemList := ItemListHnd(DialogPeek(aDialog)^.items);
  345.  
  346.         (* If the item is indeed a static text item, then set it *)
  347.         IF itemList^^ [itemNum].itemType = statText THEN
  348.             typeInfo := itemList ^^ [itemNum].itemTypeInfo
  349.     END;
  350.  
  351.  
  352. {$S DialogUtils}
  353. (*******************************************************************************
  354. * Public: DrawDialogItems
  355. *
  356. * The item list of a dialog box is stored in the "items" field of the
  357. * DialogRecord.  This routine loops through every dialog item and draws whatever
  358. * item types it understands.  Currently, this is static text items and icons.
  359. *******************************************************************************)
  360.  
  361.     PROCEDURE DrawDialogItems (aDialog: DialogPtr);
  362.  
  363.         VAR
  364.             itemNum:    Integer;     {Item number of item we’re installing}
  365.             itemList:   ItemListHnd; {Handle to the item list}
  366.             itemRect:   Rect;        {Rectangle of dialog item}
  367.             staticText: Handle;      {Handle to static text}
  368.  
  369.     BEGIN
  370.         (* Draw any static text items or icon items in the item list*)
  371.         itemList := ItemListHnd(DialogPeek(aDialog)^.items);
  372.         itemNum := 0;
  373.         WHILE itemList^^ [itemNum].itemType <> kNoItem DO
  374.             BEGIN
  375.                 IF itemList^^ [itemNum].itemType = statText THEN
  376.                     BEGIN
  377.                         (* Item is a static text item; call TextBox if there’s text *)
  378.                         staticText := itemList^^ [itemNum].itemText;
  379.                         IF GetHandleSize (staticText) > 0 THEN
  380.                             BEGIN
  381.                                 TextFont (itemList^^ [itemNum].itemTypeInfo.typeFace);
  382.                                 TextSize (itemList^^ [itemNum].itemTypeInfo.typeSize);
  383.                                 TextFace (itemList^^ [itemNum].itemTypeInfo.typeStyle);
  384.                                 itemRect := itemList^^ [itemNum].displayRect;
  385.                                 HLock (staticText);
  386.                                 TextBox (staticText^, GetHandleSize (staticText),
  387.                                         itemRect, itemList^^ [itemNum].itemTypeInfo.
  388.                                         textJust);
  389.                                 HUnlock (statictext)
  390.                             END
  391.                     END;
  392.                 itemNum := itemNum + 1
  393.             END
  394.     END;
  395.  
  396.  
  397. {$S DialogUtils}
  398. (*******************************************************************************
  399. * Public: GetDialogItemRect
  400. *
  401. * The item list of a dialog box is in the "items" field of the DialogRecord.
  402. * This handle is retrieved and the displayRect of the specified item into
  403. * "itemRect".
  404. *******************************************************************************)
  405.  
  406.     PROCEDURE GetDialogItemRect (aDialog:      DialogPtr;
  407.                                  itemNum:      Integer;
  408.                                  VAR itemRect: Rect);
  409.  
  410.         VAR
  411.             itemList: ItemListHnd; {Handle to item list}
  412.  
  413.     BEGIN
  414.         (* Grab the item list from the dialog window’s refCon *)
  415.         itemList := ItemListHnd(DialogPeek(aDialog)^.items);
  416.  
  417.         (* Copy the item’s display rectangle *)
  418.         itemRect := itemList^^ [itemNum].displayRect
  419.     END;
  420.  
  421.  
  422. {$S DialogUtils}
  423. (*******************************************************************************
  424. * Public: DisposeDialogItems
  425. *
  426. * A handle to the dialog box’s dialog item list is retrieved from the
  427. * DialogRecord’s "items" handle.  The type of each item is checked, and the
  428. * memory taken by that item is disposed of appropriately.
  429. *******************************************************************************)
  430.  
  431.     PROCEDURE DisposeDialogItems (aDialog: DialogPtr);
  432.  
  433.         VAR
  434.             itemNum:  Integer;     {Item number of item we’re installing}
  435.             itemList: ItemListHnd; {Handle to the item list}
  436.  
  437.     BEGIN
  438.         (* Grab the item list from the dialog window’s refCon *)
  439.         itemList := ItemListHnd(DialogPeek(aDialog)^.items);
  440.  
  441.         (* Starting at item 1, go through entire list and dispose of each item *)
  442.         IF itemList <> NIL THEN
  443.             BEGIN
  444.                 itemNum := 0;
  445.                 WHILE itemList^^ [itemNum].itemType <> kNoItem DO
  446.                     BEGIN
  447.                         WITH itemList^^ [itemNum] DO
  448.                             BEGIN
  449.                                 IF (*WITH*)itemType = ctrlItem + btnCtrl THEN
  450.                                     BEGIN
  451.                                         IF (*WITH*)itemControl <> NIL THEN
  452.                                             DisposeControl ((*WITH*)itemControl)
  453.                                     END
  454.                                 ELSE IF (*WITH*)itemType = statText THEN
  455.                                     BEGIN
  456.                                         IF (*WITH*)itemText <> NIL THEN
  457.                                             DisposHandle ((*WITH*)itemText)
  458.                                     END
  459.                             END;
  460.  
  461.                         (* Go on to the next item in the item list *)
  462.                         itemNum := itemNum + 1
  463.                     END;
  464.                 DisposHandle (Handle(itemList))
  465.             END
  466.     END;
  467.